using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using PHSRAG.Insight.Agreements.Arra;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.Policy;
using PHSRAG.Utility;
using System.Collections.Generic;

namespace PHSRAG.Insight.Agreements
{
    public partial class ArraPIQuestionnairePage : CachePage
    {
        #region Constants

        private const string CacheKey = "ArraPIQuestionnairePage_8c43b12a-b3f9-4700-93a0-c21658143c89";
        protected const string ConfigKeyArraPIQuestionnaireListUrl = "SubNavigation.Agreements.ArraPIQuestionnaireListURL";
        private const string ConfigKeyArraPIQuestionnaireUrl = "SubNavigation.Agreements.ArraPIQuestionnaireURL";
        private const string ConfigKeyBreadCrumbDetailPageLevel = "BreadCrumb.DetailPageLevel";
        private const string ControlNameBaseCvJobTitle = "cvJobTitle";
        private const string ControlNameBaseCvJobType = "cvJobType";
        private const string ControlNameBaseCvPercentEffort = "cvPercentEffort";
        protected const string ControlNameBaseDdlJobType = "ddlJobType";
        protected const string ControlNameBaseTrJob = "trJob";
        protected const string ControlNameBaseTxtJobTitle = "txtJobTitle";
        protected const string ControlNameBaseTxtPercentEffort = "txtPercentEffort";
        protected const string CssClassNameDataGridAlternatingItem = "DataGridAlternatingItem";
        protected const string CssClassNameDataGridItem = "DataGridItem";
        private const string ErrorMessagePIQuestionnaireNotFound = "Requested PI questionnaire could not be found.";
        private const int InitialJobTableRowCount = 5;
        private const string PageName = "PI Questionnaire";
        private const string QueryStringParamNamePIQuestionnaireID = "id";

        #endregion

        #region Constructors

        public ArraPIQuestionnairePage() : base(CacheKey)
        {
        }

        #endregion

        #region Private Variables

        private PIQuestionnaire piQuestionnaire;
        private int piQuestionnaireIDRequested;

        #endregion

        #region Overrides of Page

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Page.PreInit"/> event at the beginning of page initialization.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
        protected override void OnPreInit(EventArgs e)
        {
            Init += OnPageInit;
            Load += OnPageLoad;
            base.OnPreInit(e);
        }

        #endregion

        #region Properties

        protected PIQuestionnaire PIQuestionnaire
        {
            get
            {
                piQuestionnaire = ResultsCache.GetObject(PrevailingPageCachePolicy, PIQuestionnaire.PIQuestionnaireCacheKey) as PIQuestionnaire;

                if (piQuestionnaire == null || piQuestionnaire.Id != piQuestionnaireIDRequested)
                {
                    piQuestionnaire = new PIQuestionnaire(PrevailingPageCachePolicy);

                    if (piQuestionnaireIDRequested != 0)
                    {
                        piQuestionnaire.Load(DataAccess.ConnectionString, new object[] {piQuestionnaireIDRequested, true});
                        ResultsCache.SetObject(PrevailingCachePolicy, PIQuestionnaire.PIQuestionnaireCacheKey, piQuestionnaire);
                    }
                }

                return piQuestionnaire;
            }

            set { piQuestionnaire = value; }
        }

        #endregion

        #region Event Handlers

        private void OnPageInit(object sender, EventArgs e)
        {
            int.TryParse(Request.QueryString[QueryStringParamNamePIQuestionnaireID], out piQuestionnaireIDRequested);

            if (IsPostBack)
            {
                AddJobTableRows(string.IsNullOrEmpty(Request.Form[hdnJobRowCount.ID]) ? 0 : int.Parse(Request.Form[hdnJobRowCount.ID]));
            }
        }

        protected void OnPageLoad(object sender, EventArgs e)
        {
            breadCrumb.Add(PageName,
                Settings.GetKeyValue(ConfigKeyArraPIQuestionnaireUrl, ""),
                Settings.GetKeyValue(ConfigKeyBreadCrumbDetailPageLevel, 2));

            annunciator.Message = string.Empty;

            if (!IsPostBack)
            {
                if (piQuestionnaireIDRequested != 0)
                {
                    LoadPageData();
                }
                else
                {
                    divContent.Visible = false;
                    DisplayExceptionReport(annunciator, ErrorMessagePIQuestionnaireNotFound);
                }
            }
        }

        private void OnValidatePercentEffort(object source, ServerValidateEventArgs args)
        {
            int percentEffort;
            args.IsValid = false;

            if (int.TryParse(args.Value, out percentEffort))
            {
                if (percentEffort <= 100 && percentEffort >= 0)
                {
                    args.IsValid = true;
                    return;
                }
            }

            CustomValidator cvPercentEffort = source as CustomValidator;
            int rowNumber = int.Parse(cvPercentEffort.ID.Replace(ControlNameBaseCvPercentEffort, string.Empty));
            DropDownList ddlJobType = tblJobs.FindControl(ControlNameBaseDdlJobType + rowNumber) as DropDownList;
            TextBox txtJobTitle = tblJobs.FindControl(ControlNameBaseTxtJobTitle + rowNumber) as TextBox;

            if (string.IsNullOrEmpty(args.Value) && ddlJobType.SelectedItem.Value == "0" && string.IsNullOrEmpty(txtJobTitle.Text))
            {
                args.IsValid = true;
                return;
            }
        }

        private void OnValidateJobTitle(object source, ServerValidateEventArgs args)
        {
            args.IsValid = false;

            CustomValidator cvJobTitle = source as CustomValidator;
            int rowNumber = int.Parse(cvJobTitle.ID.Replace(ControlNameBaseCvJobTitle, string.Empty));
            DropDownList ddlJobType = tblJobs.FindControl(ControlNameBaseDdlJobType + rowNumber) as DropDownList;
            TextBox txtPercentEffort = tblJobs.FindControl(ControlNameBaseTxtPercentEffort + rowNumber) as TextBox;

            if ((!string.IsNullOrEmpty(args.Value)) ||
                (string.IsNullOrEmpty(args.Value) && ddlJobType.SelectedItem.Value == "0" && string.IsNullOrEmpty(txtPercentEffort.Text)))
            {
                args.IsValid = true;
                return;
            }
        }

        private void OnValidateJobType(object source, ServerValidateEventArgs args)
        {
            args.IsValid = false;

            if (args.Value != "0")
            {
                args.IsValid = true;
            }

            CustomValidator cvJobType = source as CustomValidator;
            int rowNumber = int.Parse(cvJobType.ID.Replace(ControlNameBaseCvJobType, string.Empty));
            TextBox txtJobTitle = tblJobs.FindControl(ControlNameBaseTxtJobTitle + rowNumber) as TextBox;
            TextBox txtPercentEffort = tblJobs.FindControl(ControlNameBaseTxtPercentEffort + rowNumber) as TextBox;

            if ((args.Value != "0") ||
                (args.Value == "0" && string.IsNullOrEmpty(txtJobTitle.Text) && string.IsNullOrEmpty(txtPercentEffort.Text)))
            {
                args.IsValid = true;
                return;
            }
        }

        protected void OnImgBtnSaveDraftClick(object sender, ImageClickEventArgs e)
        {
            if (!Page.IsValid)
            {
                return;
            }

            SavePIQuestionnaire(PIQuestionnaireState.InProcess);
        }

        protected void OnImgBtnCompleteClick(object sender, ImageClickEventArgs e)
        {
            if (!Page.IsValid)
            {
                return;
            }

            SavePIQuestionnaire(PIQuestionnaireState.Completed);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Adds the new job table row into the job table.
        /// </summary>
        /// <param name="rowNumber">The row number of the row being added.</param>
        private void AddNewJobTableRow(int rowNumber)
        {
            HtmlTableRow row = new HtmlTableRow();
            row.ID = ControlNameBaseTrJob + rowNumber;

            if ((rowNumber%2) == 0)
            {
                row.Attributes.Add("class", CssClassNameDataGridItem);
            }
            else
            {
                row.Attributes.Add("class", CssClassNameDataGridAlternatingItem);
            }

            HtmlTableCell cellJobType = new HtmlTableCell();

            DropDownList ddlJobType = new DropDownList();
            ddlJobType.AppendDataBoundItems = true;
            ddlJobType.ID = ControlNameBaseDdlJobType + rowNumber;
            ddlJobType.Items.Add(new ListItem("Select", "0"));
            ddlJobType.DataSource = PIQuestionnaire.JobTypes;
            ddlJobType.DataTextField = "Value";
            ddlJobType.DataValueField = "Key";
            ddlJobType.DataBind();
            ddlJobType.Attributes.Add("onchange", "CalculateNumberOfJobs()");
            cellJobType.Controls.Add(ddlJobType);

            CustomValidator cvJobType = new CustomValidator();
            cvJobType.ID = ControlNameBaseCvJobType + rowNumber;
            cvJobType.ErrorMessage = "Please select job type on line " + rowNumber + ".";
            cvJobType.ControlToValidate = ddlJobType.ID;
            cvJobType.EnableClientScript = false;
            cvJobType.ServerValidate += OnValidateJobType;
            cvJobType.ValidateEmptyText = true;
            cvJobType.Display = ValidatorDisplay.Dynamic;
            cvJobType.Text = "*";
            cvJobType.Font.Size = new FontUnit(FontSize.Large);
            cellJobType.Controls.Add(cvJobType);

            HtmlTableCell cellJobTitle = new HtmlTableCell();

            TextBox txtJobTitle = new TextBox();
            txtJobTitle.ID = ControlNameBaseTxtJobTitle + rowNumber;
            txtJobTitle.MaxLength = 40;
            txtJobTitle.Width = 300;
            cellJobTitle.Controls.Add(txtJobTitle);

            CustomValidator cvJobTitle = new CustomValidator();
            cvJobTitle.ID = ControlNameBaseCvJobTitle + rowNumber;
            cvJobTitle.ErrorMessage = "Please enter job title on line " + rowNumber + ".";
            cvJobTitle.ControlToValidate = txtJobTitle.ID;
            cvJobTitle.EnableClientScript = false;
            cvJobTitle.ServerValidate += OnValidateJobTitle;
            cvJobTitle.ValidateEmptyText = true;
            cvJobTitle.Text = "*";
            cvJobTitle.Font.Size = new FontUnit(FontSize.Large);
            cellJobTitle.Controls.Add(cvJobTitle);

            HtmlTableCell cellPercentEffort = new HtmlTableCell();

            TextBox txtPercentEffort = new TextBox();
            txtPercentEffort.ID = ControlNameBaseTxtPercentEffort + rowNumber;
            txtPercentEffort.MaxLength = 3;
            txtPercentEffort.Width = 50;
            txtPercentEffort.Attributes.Add("onkeyup", "CalculateNumberOfJobs()");
            cellPercentEffort.Controls.Add(txtPercentEffort);
            cellPercentEffort.PreRender += OnCellPercentEffortPreRender;

            CustomValidator cvPercentEffort = new CustomValidator();
            cvPercentEffort.ID = ControlNameBaseCvPercentEffort + rowNumber;
            cvPercentEffort.ErrorMessage = "Please enter a non-decimal numeric effort percentage (less that 100%) on line " + rowNumber + ".";
            cvPercentEffort.ControlToValidate = txtPercentEffort.ID;
            cvPercentEffort.EnableClientScript = false;
            cvPercentEffort.ServerValidate += OnValidatePercentEffort;
            cvPercentEffort.ValidateEmptyText = true;
            cvPercentEffort.Text = "*";
            cvPercentEffort.Font.Size = new FontUnit(FontSize.Large);
            cellPercentEffort.Controls.Add(cvPercentEffort);

            row.Cells.Add(cellJobType);
            row.Cells.Add(cellJobTitle);
            row.Cells.Add(cellPercentEffort);

            tblJobs.Rows.Insert(tblJobs.Rows.Count - 2, row);
        }

        private void OnCellPercentEffortPreRender(object sender, EventArgs e)
        {
            Literal ltrPercentSign = new Literal();
            ltrPercentSign.Text = "%";
            (sender as HtmlTableCell).Controls.Add(ltrPercentSign);
        }

        /// <summary>
        /// Adds the job table rows.
        /// </summary>
        /// <param name="rowCount">The row count.</param>
        private void AddJobTableRows(int rowCount)
        {
            for (int i = 1; i <= rowCount; i++)
            {
                AddNewJobTableRow(i);
            }
        }

        private void LoadPageData()
        {
            if (PIQuestionnaire.Id != 0)
            {
                lblPI.Text = PIQuestionnaire.PIName;
                lblProjectTitle.Text = PIQuestionnaire.ProjectTitle;
                lblPeopleSoftNumber.Text = PIQuestionnaire.PeopleSoftNumber;
                lblChiefOfServiceCode.Text = PIQuestionnaire.ChiefCode;
                lblOrganization.Text = PIQuestionnaire.Organization;
                lblDept.Text = PIQuestionnaire.Department;
                lblSponsor.Text = PIQuestionnaire.Sponsor;
                lblSponsorAwardNumber.Text = PIQuestionnaire.SponsorAwardNumber;
                lblQuarterEndingOn.Text = PIQuestionnaire.QuarterEndDtm.ToShortDateString();
                lblDeptAdmin.Text = PIQuestionnaire.DepartmentAdmin;
                lblResearchMgmtAdmin.Text = PIQuestionnaire.ResearchMgmtAdmin;
                txtAwardDescription.Text = PIQuestionnaire.Narrative;
                txtProjectDescription.Text = PIQuestionnaire.QuarterlyActivitiesDescription;

                if (PIQuestionnaire.Jobs.Count < 1)
                {
                    hdnJobRowCount.Value = InitialJobTableRowCount.ToString();
                    AddJobTableRows(InitialJobTableRowCount);
                }
                else
                {
                    hdnJobRowCount.Value = PIQuestionnaire.Jobs.Count.ToString();
                    AddJobTableRows(PIQuestionnaire.Jobs.Count);

                    for (int i = 1; i <= PIQuestionnaire.Jobs.Count; ++i)
                    {
                        ((DropDownList) tblJobs.FindControl(ControlNameBaseDdlJobType + i)).SelectedValue = PIQuestionnaire.Jobs[i - 1].TypeID.ToString();
                        ((TextBox) tblJobs.FindControl(ControlNameBaseTxtJobTitle + i)).Text = PIQuestionnaire.Jobs[i - 1].Title;
                        ((TextBox) tblJobs.FindControl(ControlNameBaseTxtPercentEffort + i)).Text = PIQuestionnaire.Jobs[i - 1].PercentEffort.ToString();
                    }
                }

                // make form read only if questionnaire is completed
                if (PIQuestionnaire.State == PIQuestionnaireState.Completed)
                {
                    divJobButtons.Visible = false;
                    divSaveButtons.Visible = false;
                    MakePageReadOnly();
                }

            }
            else
            {
                divContent.Visible = false;
                DisplayExceptionReport(annunciator, ErrorMessagePIQuestionnaireNotFound);
            }
        }

        /// <summary>
        /// Replaces editable page controls with labels with the same text.
        /// </summary>
        private void MakePageReadOnly()
        {
            lblAwardDescription.Text = txtAwardDescription.Text;
            divAwardDescription.Visible = false;
            divAwardDescriptionReadOnly.Visible = true;

            lblProjectDescription.Text = txtProjectDescription.Text;
            divProjectDescription.Visible = false;
            divProjectDescriptionReadOnly.Visible = true;

            MakeReadOnly(tblJobs.Controls);
        }

        /// <summary>
        /// Replaces editable controls in the list with labels with the same text.
        /// </summary>
        /// <param name="controls">Control list containing editable controls (not only) to replace with labels.</param>
        private static void MakeReadOnly(ControlCollection controls)
        {
            // Dictionary of labels and controls to add those labels to.
            // This list will be used to keep references to the controls 
            // while iterating through the list of them
            IDictionary<Label, Control> labelsToAdd = new Dictionary<Label, Control>();

            foreach (Control ctrl in controls)
            {
                if (ctrl is DropDownList || ctrl is TextBox)
                {
                    WebControl webControl = (ctrl as WebControl);
                    Label lbl = new Label();

                    if (webControl is TextBox)
                    {
                        lbl.Text = (webControl as TextBox).Text;
                    }
                    else
                    {
                        lbl.Text = (webControl as DropDownList).SelectedItem.Text;
                    }

                    labelsToAdd.Add(lbl, webControl.Parent);
                    webControl.CssClass = "ControlHidden";
                }

                if (ctrl.Controls.Count > 0)
                {
                    MakeReadOnly(ctrl.Controls);
                }
            }

            // Add labels to parent controls
            foreach (KeyValuePair<Label, Control> pair in labelsToAdd)
            {
                pair.Value.Controls.Add(pair.Key);
            }
        }

        /// <summary>
        /// Saves PI questionnaire to DB and sets it's status to the passed in status.
        /// </summary>
        /// <param name="state">State of PI questionnaire.</param>
        private void SavePIQuestionnaire(PIQuestionnaireState state)
        {
            UserContext userContext = PrevailingCachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;

            PIQuestionnaire.Dirty = true;
            PIQuestionnaire.Narrative = txtAwardDescription.Text;
            PIQuestionnaire.QuarterlyActivitiesDescription = txtProjectDescription.Text;

            PIQuestionnaire.Jobs.Clear();

            for (int i = 1; i <= int.Parse(hdnJobRowCount.Value); i++)
            {
                string jobTypeIDValue = (tblJobs.FindControl(ControlNameBaseDdlJobType + i) as DropDownList).SelectedValue;
                string jobTitleText = (tblJobs.FindControl(ControlNameBaseTxtJobTitle + i) as TextBox).Text;
                string percentEffortText = (tblJobs.FindControl(ControlNameBaseTxtPercentEffort + i) as TextBox).Text;

                if (jobTypeIDValue != "0" && !string.IsNullOrEmpty(jobTitleText) && !string.IsNullOrEmpty(percentEffortText))
                {

                    Job job = new Job();
                    job.TypeID = int.Parse(jobTypeIDValue);
                    job.Title = jobTitleText;
                    job.PercentEffort = int.Parse(percentEffortText);
                    PIQuestionnaire.Jobs.Add(job);
                }
            }

            PIQuestionnaire.PersonID = userContext.PersonId;
            PIQuestionnaire.State = state;
            PIQuestionnaire.Save(DataAccess.ConnectionString);

            Response.Redirect(Settings.GetKeyValue(ConfigKeyArraPIQuestionnaireListUrl, string.Empty));
        }

        #endregion
    }
}